package org.dromara.system.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.system.constants.OrderConstants;
import org.dromara.system.utils.RequestUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.PayRateBo;
import org.dromara.system.domain.vo.PayRateVo;
import org.dromara.system.domain.PayRate;
import org.dromara.system.mapper.PayRateMapper;
import org.dromara.system.service.IPayRateService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 汇率Service业务层处理
 *
 * @author Gavino
 * @date 2024-10-22
 */
@RefreshScope
@RequiredArgsConstructor
@Service
public class PayRateServiceImpl implements IPayRateService {

    private final PayRateMapper baseMapper;

    @Value("${rateUrl}")
    public String rateUrl;
    @Value("${rateUp}")
    public String rateUp;

    @Override
    public PayRate selectByCurrency(String currency) {
        PayRate obj = RedisUtils.getCacheObject(OrderConstants.pay_rate + currency);
        if (obj == null) {
            obj = baseMapper.selectOne(new QueryWrapper<PayRate>().eq("code", currency).last("limit 1"));
            if (obj != null) {
                RedisUtils.setCacheObject(OrderConstants.pay_rate + currency, obj);
            }
        }
        return obj;
    }

    /**
     * 刷新汇率
     *
     * @return 结果
     */
    @Transactional
    @Override
    public R<?> refresh() {

        String resStr = new RequestUtils().doGet(rateUrl);
        if (StringUtils.isEmpty(resStr)) {
            return R.fail("请求失败");
        }

        JSONObject json = JSONObject.parseObject(resStr);

        if (!"success".equals(json.getString("result"))) {
            return R.fail("请求失败");
        }

        JSONObject jsonObj = json.getJSONObject("conversion_rates");

        if (jsonObj == null || jsonObj.keySet().size() == 0) {
            return R.fail("未拉起到数据");
        }

        List<PayRate> list = new ArrayList<>();
        AtomicInteger i = new AtomicInteger();
        jsonObj.keySet().forEach((key) -> {
            PayRate payRate = new PayRate();
            payRate.setCode(key);

            BigDecimal rate = jsonObj.getBigDecimal(key);
            if (StringUtils.isNotBlank(rateUp) && !Objects.equals("CNY", key) && !Objects.equals("USD", key)) {
                rate = rate.multiply(new BigDecimal(rateUp)).setScale(4, RoundingMode.HALF_UP);
            }
            payRate.setValue(rate.toPlainString());
            payRate.setCreateTime(new Date());
            payRate.setUpdateTime(new Date());
            if (Objects.equals("CNY", key)) {
                payRate.setSort(-1);
            } else {
                payRate.setSort(i.getAndIncrement());
            }
            list.add(payRate);
            RedisUtils.setCacheObject(OrderConstants.pay_rate + key, payRate);
        });

        if (list.size() > 0) {
            if (baseMapper.delete(new QueryWrapper<>()) > 0) {
                baseMapper.insertBatch(list);
            }
        }

        return R.ok();
    }

    /**
     * 查询汇率
     *
     * @param rateId 主键
     * @return 汇率
     */
    @Override
    public PayRateVo queryById(Long rateId) {
        return baseMapper.selectVoById(rateId);
    }

    /**
     * 查询汇率
     *
     * @return 汇率
     */
    @Override
    public Date updateTime() {
        return baseMapper.selectVoOne(new QueryWrapper<PayRate>().eq("code", "USD").last("limit 1")).getUpdateTime();
    }

    /**
     * 分页查询汇率列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 汇率分页列表
     */
    @Override
    public TableDataInfo<PayRateVo> queryPageList(PayRateBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<PayRate> lqw = buildQueryWrapper(bo);
        Page<PayRateVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的汇率列表
     *
     * @param bo 查询条件
     * @return 汇率列表
     */
    @Override
    public List<PayRateVo> queryList(PayRateBo bo) {
        LambdaQueryWrapper<PayRate> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<PayRate> buildQueryWrapper(PayRateBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PayRate> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getCode()), PayRate::getCode, bo.getCode());
        lqw.eq(StringUtils.isNotBlank(bo.getValue()), PayRate::getValue, bo.getValue());
        lqw.orderByAsc(PayRate::getSort);
        return lqw;
    }

    /**
     * 新增汇率
     *
     * @param bo 汇率
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(PayRateBo bo) {
        PayRate add = MapstructUtils.convert(bo, PayRate.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setRateId(add.getRateId());
        }
        return flag;
    }

    /**
     * 修改汇率
     *
     * @param bo 汇率
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(PayRateBo bo) {
        PayRate update = MapstructUtils.convert(bo, PayRate.class);
        validEntityBeforeSave(update);
        RedisUtils.deleteObject(OrderConstants.pay_rate + bo.getCode());
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(PayRate entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除汇率信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }
}
